﻿// Microsoft Public License (Ms-PL)
//
// This license governs use of the accompanying software. If you use the software, you accept this license.
// If you do not accept the license, do not use the software.
//
// 1. Definitions
//
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here 
// as under U.S. copyright law.
//
// A "contribution" is the original software, or any additions or changes to the software.
//
// A "contributor" is any person that distributes its contribution under this license.
//
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
//
// 2. Grant of Rights
//
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations 
// in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to 
// reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution 
// or any derivative works that you create.
//
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in 
// section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed 
// patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution 
// in the software or derivative works of the contribution in the software.
//
// 3. Conditions and Limitations
//
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or 
// trademarks.
//
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the 
// software, your patent license from such contributor to the software ends automatically.
//
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and 
// attribution notices that are present in the software.
//
// (D) If you distribute any portion of the software in source code form, you may do so only under this license 
// by including a complete copy of this license with your distribution. If you distribute any portion of the 
// software in compiled or object code form, you may only do so under a license that complies with this license.
//
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express 
// warranties, guarantees or conditions. You may have additional consumer rights under your local laws which 
// this license cannot change. To the extent permitted under your local laws, the contributors exclude the 
// implied warranties of merchantability, fitness for a particular purpose and non-infringement.

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Services.Protocols;
using System.Xml;

namespace StructuredSolutions.ShippingAgent
{
    public class DetailedSoapException : SoapException
    {
        public DetailedSoapException(string message, XmlQualifiedName code, Exception innerException) : base(message, code, Assembly.GetExecutingAssembly().FullName, CreateDetailNode(innerException), innerException)
        {
        }

        private static XmlNode CreateDetailNode(Exception innerException)
        {
            XmlDocument doc = new XmlDocument();
            XmlNode url = doc.CreateElement("url");
            if ((HttpContext.Current != null))
                url.InnerText = HttpContext.Current.Request.Url.ToString();
            XmlNode innerExceptionType = doc.CreateElement("innerExceptionType");
            innerExceptionType.InnerText = innerException.GetType().ToString();
            XmlNode innerExceptionMessage = doc.CreateElement("innerExceptionMessage");
            Exception innermostException = innerException;
            while ((innermostException.InnerException != null))
                innermostException = innermostException.InnerException;
            // By assigning the message to InnerText and then writing InnerXml to innerText, 
            // I end up encoding the message. For example, if the message include a non-printing 
            // character such as CHAR(0), the final innerText will look like '&amp;;#0'. If I don't 
            // do the second assignment, the innerText will be '&#0' which is not valid XML text. 
            innerExceptionMessage.InnerText = innermostException.Message;
            innerExceptionMessage.InnerText = innerExceptionMessage.InnerXml;
            XmlNode innerExceptionString = doc.CreateElement("innerExceptionString");
            innerExceptionString.InnerText = innerException.ToString();
            innerExceptionString.InnerText = innerExceptionString.InnerXml;
            XmlNode assemblies = doc.CreateElement("assemblies");
            string basepath = null;
            if (HttpContext.Current != null && HttpContext.Current.Request != null)
                basepath = HttpContext.Current.Request.PhysicalApplicationPath;
            if (!string.IsNullOrEmpty(basepath))
            {
                try
                {
                    foreach (string filename in Directory.GetFiles(Path.Combine(basepath, "bin")))
                    {
                        if (Path.GetExtension(filename).ToLower().EndsWith(".dll"))
                        {
                            XmlNode a = doc.CreateElement("assembly");
                            assemblies.AppendChild(a);
                            a.InnerText = string.Format("{0}: {1}", Path.GetFileName(filename), FileVersionInfo.GetVersionInfo(filename).FileVersion);
                        }
                    }
                }
#pragma warning disable EmptyGeneralCatchClause
                catch
#pragma warning restore EmptyGeneralCatchClause
                {
                    // Ignore permission errors 
                }
            }
            XmlNode detail = doc.CreateElement("detail");
            detail.AppendChild(url);
            detail.AppendChild(innerExceptionType);
            detail.AppendChild(innerExceptionMessage);
            detail.AppendChild(innerExceptionString);
            detail.AppendChild(assemblies);
            return detail;
        }
    }
}
